<script lang="ts" setup>
import { useClipboard } from '@vueuse/core'
import { ElMessage } from 'element-plus'
import { computed, ref } from 'vue'

const jwtToken = ref('')
const { copy } = useClipboard()

// 解析后的JWT部分
const header = ref<any>(null)
const payload = ref<any>(null)
const signature = ref('')

// 格式化的JSON字符串
const formattedHeader = computed(() => {
  return header.value ? JSON.stringify(header.value, null, 2) : ''
})

const formattedPayload = computed(() => {
  return payload.value ? JSON.stringify(payload.value, null, 2) : ''
})

// 解析JWT令牌
function parseJwt() {
  if (!jwtToken.value.trim()) {
    ElMessage.warning('请输入JWT令牌')
    return
  }

  try {
    // 分割JWT令牌的三个部分
    const parts = jwtToken.value.split('.')
    if (parts.length !== 3) {
      throw new Error('无效的JWT格式，应该包含三个由点(.)分隔的部分')
    }

    // 解码头部
    const decodedHeader = decodeBase64Url(parts[0])
    header.value = JSON.parse(decodedHeader)

    // 解码载荷
    const decodedPayload = decodeBase64Url(parts[1])
    payload.value = JSON.parse(decodedPayload)

    // 保存签名（不解码，因为它是二进制数据）
    signature.value = parts[2]

    ElMessage.success('JWT解析成功')
  }
  catch (error) {
    ElMessage.error(`JWT解析失败: ${(error as Error).message}`)
    clearResults()
  }
}

// 解码Base64Url编码的字符串
function decodeBase64Url(str: string): string {
  // 将Base64Url转换为标准Base64
  let base64 = str.replace(/-/g, '+').replace(/_/g, '/')
  // 添加填充
  while (base64.length % 4) {
    base64 += '='
  }
  // 解码
  return decodeURIComponent(
    atob(base64)
      .split('')
      .map(c => `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}`)
      .join(''),
  )
}

// 复制结果
function copyResult(text: string, type: string) {
  if (!text) {
    ElMessage.warning(`没有可复制的${type}内容`)
    return
  }

  copy(text)
  ElMessage.success(`已复制${type}到剪贴板`)
}

// 清空输入
function clearInput() {
  jwtToken.value = ''
  clearResults()
}

// 清空结果
function clearResults() {
  header.value = null
  payload.value = null
  signature.value = ''
}

// 检查是否有过期时间并计算剩余时间
const expirationInfo = computed(() => {
  if (!payload.value || !payload.value.exp) {
    return null
  }

  const expTimestamp = payload.value.exp * 1000 // 转换为毫秒
  const now = Date.now()
  const isExpired = now > expTimestamp

  if (isExpired) {
    return {
      status: 'expired',
      message: `已过期于 ${new Date(expTimestamp).toLocaleString()}`,
    }
  }
  else {
    const diff = expTimestamp - now
    const days = Math.floor(diff / (1000 * 60 * 60 * 24))
    const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
    const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60))

    return {
      status: 'valid',
      message: `有效期还剩 ${days}天 ${hours}小时 ${minutes}分钟 (${new Date(expTimestamp).toLocaleString()})`,
    }
  }
})

// 检查是否有颁发时间
const issuedAtInfo = computed(() => {
  if (!payload.value || !payload.value.iat) {
    return null
  }

  const iatTimestamp = payload.value.iat * 1000 // 转换为毫秒
  return `颁发于 ${new Date(iatTimestamp).toLocaleString()}`
})
</script>

<template>
  <div class="mx-auto p-6">
    <div class="flex flex-col space-y-6">
      <!-- 输入区域 -->
      <div>
        <div class="mb-2 flex items-center">
          <span class="text-gray-700 font-medium">JWT令牌</span>
        </div>
        <textarea
          v-model="jwtToken"
          class="h-32 w-full border rounded p-2 font-mono"
          placeholder="请输入JWT令牌"
        />
      </div>

      <!-- 操作按钮 -->
      <div class="flex flex-wrap justify-center gap-4">
        <button
          class="flex items-center gap-2 rounded-lg bg-blue-600 px-6 py-2.5 text-white shadow-sm transition-colors hover:bg-blue-700"
          @click="parseJwt"
        >
          <i class="el-icon-refresh-right" />解析JWT
        </button>
        <button
          class="flex items-center gap-2 rounded-lg bg-red-600 px-6 py-2.5 text-white shadow-sm transition-colors hover:bg-red-700"
          @click="clearInput"
        >
          <i class="el-icon-delete" />清空
        </button>
      </div>

      <!-- 解析结果 -->
      <div v-if="header || payload" class="mt-4 space-y-6">
        <!-- 过期信息 -->
        <div v-if="expirationInfo" class="rounded-lg p-3" :class="expirationInfo.status === 'valid' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'">
          <div class="flex items-center">
            <i :class="expirationInfo.status === 'valid' ? 'el-icon-success' : 'el-icon-error'" class="mr-2" />
            <span>{{ expirationInfo.message }}</span>
          </div>
        </div>

        <!-- 颁发时间 -->
        <div v-if="issuedAtInfo" class="rounded-lg bg-blue-100 p-3 text-blue-800">
          <div class="flex items-center">
            <i class="el-icon-time mr-2" />
            <span>{{ issuedAtInfo }}</span>
          </div>
        </div>

        <!-- 头部 -->
        <div>
          <div class="mb-2 flex items-center">
            <span class="text-gray-700 font-medium">头部 (Header)</span>
            <button
              class="ml-2 text-blue-600 hover:text-blue-800"
              title="复制头部"
              @click="copyResult(formattedHeader, '头部')"
            >
              <i class="el-icon-document-copy" />
            </button>
          </div>
          <pre class="max-h-64 overflow-auto rounded bg-gray-100 p-4">{{ formattedHeader }}</pre>
        </div>

        <!-- 载荷 -->
        <div>
          <div class="mb-2 flex items-center">
            <span class="text-gray-700 font-medium">载荷 (Payload)</span>
            <button
              class="ml-2 text-blue-600 hover:text-blue-800"
              title="复制载荷"
              @click="copyResult(formattedPayload, '载荷')"
            >
              <i class="el-icon-document-copy" />
            </button>
          </div>
          <pre class="max-h-64 overflow-auto rounded bg-gray-100 p-4">{{ formattedPayload }}</pre>
        </div>

        <!-- 签名 -->
        <div>
          <div class="mb-2 flex items-center">
            <span class="text-gray-700 font-medium">签名 (Signature)</span>
            <button
              class="ml-2 text-blue-600 hover:text-blue-800"
              title="复制签名"
              @click="copyResult(signature, '签名')"
            >
              <i class="el-icon-document-copy" />
            </button>
          </div>
          <div class="max-h-32 overflow-auto break-all rounded bg-gray-100 p-4 font-mono">
            {{ signature }}
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
/* 自定义样式 */
</style>
